package top.jiangqiang.qianyi.common.filter.xss;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Getter;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.http.html.HtmlUtil;
import org.springframework.http.MediaType;
import top.jiangqiang.qianyi.common.filter.AbstractPathMatchingOrderedFilter;
import top.jiangqiang.qianyi.common.filter.caching.wrapper.CachingRWrapper;
import top.jiangqiang.qianyi.common.filter.caching.wrapper.CachingHttpServletRequestWrapper;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

public class XssFilter extends AbstractPathMatchingOrderedFilter {
    public XssFilter(List<String> includePatterns, int order, List<String> excludePatterns) {
        super(includePatterns, order, excludePatterns);
    }

    @Override
    protected void doEnhancedFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {

    }

    public static class XssRequestWrapper extends CachingRWrapper {
        private final byte[] data;
        /**
         * 是否已经缓存，只有需要Xss过滤的才需要缓存
         */
        @Getter
        private final boolean cached;

        private static final String[] SUPPORTED_CONTENT_TYPES = {
                MediaType.APPLICATION_JSON_VALUE,
        };

        /**
         * Constructs a request object wrapping the given request.
         *
         * @param request The request to wrap
         * @throws IllegalArgumentException if the request is null
         */
        public XssRequestWrapper(HttpServletRequest request) {
            super(request);
            if (request instanceof CachingHttpServletRequestWrapper requestWrapper && requestWrapper.isCached()) {
                String contentType = request.getContentType();
                //只缓存指定请求方式的指定contentType类型
                if (Stream.of(SUPPORTED_CONTENT_TYPES).anyMatch(s -> StrUtil.startWithIgnoreCase(contentType, s))) {
                    cached = true;
                    String contentAsString = filterXss(requestWrapper.getContentAsString());
                    this.data = contentAsString.getBytes(Charset.forName(getCharacterEncoding()));
                    return;
                }
            }
            this.cached = false;
            this.data = new byte[0];
        }

        @Override
        public byte[] getContentAsByteArray() {
            if (isCached()) {
                return this.data;
            } else {
                throw new UnsupportedOperationException();
            }
        }

        @Override
        public String getParameter(String name) {
            return filterXss(super.getParameter(name));
        }

        @Override
        public Map<String, String[]> getParameterMap() {
            Map<String, String[]> valueMap = super.getParameterMap();
            if (CollUtil.isEmpty(valueMap)) {
                return valueMap;
            }
            for (Map.Entry<String, String[]> entry : valueMap.entrySet()) {
                filterXss(entry.getValue());
            }
            return valueMap;
        }

        @Override
        public String[] getParameterValues(String name) {
            String[] values = super.getParameterValues(name);
            if (ArrayUtil.isEmpty(values)) {
                return values;
            }
            filterXss(values);
            return values;
        }

        private void filterXss(String[] values) {
            for (int i = 0; i < values.length; i++) {
                values[i] = filterXss(values[i]);
            }
        }

        public String filterXss(String content) {
            if (StrUtil.isBlank(content)) {
                return content;
            } else {
                return HtmlUtil.filter(content);
            }
        }
    }
}
